package com.leyou.item.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.leyou.common.dto.PageDTO;
import com.leyou.common.exceptions.LyException;
import com.leyou.common.utils.JsonUtils;
import com.leyou.item.dto.SkuDTO;
import com.leyou.item.dto.SpecParamDTO;
import com.leyou.item.dto.SpuDTO;
import com.leyou.item.dto.SpuDetailDTO;
import com.leyou.item.entity.*;
import com.leyou.item.mapper.SpuMapper;
import com.leyou.item.service.*;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.leyou.common.constants.MQConstants.ExchangeConstants.ITEM_EXCHANGE_NAME;
import static com.leyou.common.constants.MQConstants.RoutingKeyConstants.ITEM_DOWN_KEY;
import static com.leyou.common.constants.MQConstants.RoutingKeyConstants.ITEM_UP_KEY;

/**
 * @author 虎哥
 */
@Service
public class SpuServiceImpl extends ServiceImpl<SpuMapper, Spu> implements SpuService {

    @Autowired
    private AmqpTemplate amqpTemplate;

    @Autowired
    private BrandService brandService;
    @Autowired
    private CategoryService categoryService;
    @Autowired
    private SpuDetailService detailService;
    @Autowired
    private SkuService skuService;
    @Autowired
    private SpecParamService paramService;

    @Override
    public PageDTO<SpuDTO> querySpuByPage(Integer page, Integer rows, Boolean saleable, Long categoryId, Long brandId, Long id) {
        // 1.分页查询
        Page<Spu> result = query()
                .eq(id != null, "id", id)
                .eq(categoryId != null, "cid3", categoryId)
                .eq(brandId != null, "brand_id", brandId)
                .eq(saleable != null, "saleable", saleable)
                .page(new Page<>(page, rows));
        // 2.解析
        long total = result.getTotal();
        long totalPage = result.getPages();
        List<Spu> list = result.getRecords();

        // 2.1.转换DTO
        List<SpuDTO> spuDTOList = SpuDTO.convertEntityList(list);
        // 2.2.给SpuDTO查询品牌和分类的名称
        for (SpuDTO spuDTO : spuDTOList) {
            handleBrandAndCategoryName(spuDTO);
        }

        // 3.封装PageDTO
        return new PageDTO<>(total, totalPage, spuDTOList);
    }

    @Override
    @Transactional
    public void saveGoods(SpuDTO spuDTO) {
        // 1.新增Spu
        // 1.1.转换DTO为PO
        Spu spu = spuDTO.toEntity(Spu.class);
        // 1.2.默认下架
        spu.setSaleable(false);
        // 1.3.新增
        boolean success = save(spu);
        if (!success) {
            throw new LyException(500, "新增商品失败！");
        }
        // 1.4.获取回显的id
        Long spuId = spu.getId();

        // 2.新增SpuDetail
        SpuDetailDTO detailDTO = spuDTO.getSpuDetail();
        // 2.1.转换DTO为PO
        SpuDetail spuDetail = detailDTO.toEntity(SpuDetail.class);
        // 2.2.填写id
        spuDetail.setSpuId(spuId);
        // 2.3.写入数据库
        success = detailService.save(spuDetail);
        if (!success) {
            throw new LyException(500, "新增商品失败！");
        }

        // 3.新增Sku
        List<SkuDTO> skuDTOList = spuDTO.getSkus();
        // 3.1.转换DTO为PO
        List<Sku> skus = new ArrayList<>(skuDTOList.size());
        for (SkuDTO skuDTO : skuDTOList) {
            // dto转PO
            Sku sku = skuDTO.toEntity(Sku.class);
            skus.add(sku);
            // 填充字段
            sku.setSaleable(false);
            sku.setSpuId(spuId);
            sku.setSold(0L);
        }
        // 3.2.写入数据库
        skuService.saveBatch(skus);
    }

    @Override
    @Transactional
    public void updateSaleable(Long spuId, Boolean saleable) {
        // 1.更新spu上下架 update tb_spu set saleable = #{s} where id = #{spuId}
        Spu spu = new Spu();
        spu.setId(spuId);
        spu.setSaleable(saleable);
        boolean success = updateById(spu);
        if (!success) {
            throw new LyException(500, "更新上下架失败！");
        }
        // 2.更新sku的上下架 update tb_sku set saleable = #{s} where spu_id = #{spuId}
        success = skuService.update().set("saleable", saleable).eq("spu_id", spuId).update();
        if (!success) {
            throw new LyException(500, "更新上下架失败！");
        }

        // 发送消息
        String routingKey = saleable ? ITEM_UP_KEY : ITEM_DOWN_KEY;
        amqpTemplate.convertAndSend(ITEM_EXCHANGE_NAME, routingKey, spuId);
    }

    @Override
    public SpuDTO queryGoodsById(Long spuId) {
        // 1.查询spu
        Spu spu = getById(spuId);
        SpuDTO spuDTO = new SpuDTO(spu);
        // 2.查询spuDetail
        spuDTO.setSpuDetail(detailService.queryDetailBySpuId(spuId));
        // 3.查询sku
        spuDTO.setSkus(skuService.querySkuBySpuId(spuId));
        // 4.查询分类和品牌名称
        handleBrandAndCategoryName(spuDTO);
        return spuDTO;
    }

    @Override
    @Transactional
    public void updateGoods(SpuDTO spuDTO) {
        // 1.判断参数中是否包含spu的Id
        Long spuId = spuDTO.getId();
        if (spuId != null) {
            // 1.1.spu有变化，需要修改，转PO
            Spu spu = spuDTO.toEntity(Spu.class);
            // 1.2.确保不更新saleable
            spu.setSaleable(null);
            // 1.3.更新
            boolean success = updateById(spu);
            if (!success) {
                throw new LyException(500, "更新商品失败！");
            }
        }

        // 2.判断是否包含spuDetail
        SpuDetailDTO detailDTO = spuDTO.getSpuDetail();
        if (detailDTO != null && detailDTO.getSpuId() != null) {
            // 2.1.需要修改spuDetail，转PO
            SpuDetail detail = detailDTO.toEntity(SpuDetail.class);
            // 2.2.更新
            boolean success = detailService.updateById(detail);
            if (!success) {
                throw new LyException(500, "更新商品失败！");
            }
        }

        // 3.判断是否包含sku
        List<SkuDTO> skuDTOList = spuDTO.getSkus();
        if (CollectionUtils.isEmpty(skuDTOList)) {
            // 如果不包含sku，无需修改
            return;
        }
        // 4.把DTO转PO
        Map<Boolean, List<Sku>> skuMap = skuDTOList.stream()
                .map(skuDTO -> skuDTO.toEntity(Sku.class))
                // 5.判断是否包含saleable
                .collect(Collectors.groupingBy(sku -> sku.getSaleable() != null));
        // 6.包含saleable：就是需要删除的sku
        List<Sku> deleteSkuList = skuMap.get(true);
        // 6.1.判断是否为空
        if(!CollectionUtils.isEmpty(deleteSkuList)) {
            // 6.2.不为空，获取待删除的sku的id集合
            List<Long> deleteIdList = deleteSkuList.stream().map(Sku::getId).collect(Collectors.toList());
            // 6.3.批量删除
            skuService.removeByIds(deleteIdList);
        }
        // 7.不包含saleable：就是需要新增或修改的sku
        List<Sku> saveOrUpdateSkuList = skuMap.get(false);
        // 7.1.判断是否为空
        if(!CollectionUtils.isEmpty(saveOrUpdateSkuList)) {
            // 7.2.不为空，需要增或改
            skuService.saveOrUpdateBatch(saveOrUpdateSkuList);
        }
    }

    @Override
    public List<SpecParamDTO> querySpecValue(Long spuId, Boolean searching) {
        // 1.查询spu
        Spu spu = getById(spuId);
        // 2.获取分类信息
        Long categoryId = spu.getCid3();
        // 3.根据分类查询规格参数key   tb_spec_param
        List<SpecParamDTO> params = paramService.queryParams(categoryId, null, searching);
        // 4.查询规格参数的值	tb_spu_detail
        SpuDetail detail = detailService.getById(spuId);
        // 4.1.获取规格参数值
        String specification = detail.getSpecification();
        // 4.2.把json转为Map，key是param的id，value是param的值
        Map<Long, Object> valueMap = JsonUtils.toMap(specification, Long.class, Object.class);
        // 5.给每个param找到对应的value
        for (SpecParamDTO param : params) {
            Long id = param.getId();
            Object value = valueMap.get(id);
            param.setValue(value);
        }
        return params;
    }

    private void handleBrandAndCategoryName(SpuDTO spuDTO) {
        // 1.添加分类名称
        // 1.1.获取商品关联的三级的分类的id集合
        List<Long> categoryIds = spuDTO.getCategoryIds();
        // 1.2.查询三级分类的集合
        List<Category> categories = categoryService.listByIds(categoryIds);
        if(!CollectionUtils.isEmpty(categories)){
            // 1.3.处理分类名称
            String names = categories.stream().map(Category::getName).collect(Collectors.joining("/"));
            spuDTO.setCategoryName(names);
        }

        /*StringBuilder sb = new StringBuilder();
        for (Category category : categories) {
            sb.append(category.getName()).append(">");
        }
        sb.deleteCharAt(sb.length() - 1);
        spuDTO.setCategoryName(sb.toString());*/

        // 2.添加品牌名称
        // 2.1.获取品牌id
        Long brandId = spuDTO.getBrandId();
        // 2.2.根据品牌id查询品牌对象
        Brand brand = brandService.getById(brandId);
        // 2.3.设置品牌名称
        if (brand != null) {
            spuDTO.setBrandName(brand.getName());
        }

    }

}
